// 引用链接 https://blog.csdn.net/qq_43869822/article/details/121664818

// keyof 运算符， 获取对象所有键的类型，合并为一个字符串字面量类型， keyof 默认返回 number | string | symbol 类型 （处理具体结构时，ts将推导出该并集类型的具体子类型）， 如果要使用 ts 以前的行为，也就是必须是 string， 可以在 tsconfig.json 中启用 keyofStringOnly 标志。
// infer 关键字 在条件类型中声明泛型可以使用这个
type ElementType<T> = T extends (infer U)[] ? U : T;
type B = ElementType<number[]>; // number  是根据传给 ElementType 的 T 推导 U 的类型。

// 泛型类型 把原有的对象类型映射成新的对象类型  T,K 是类型参数 keyof 用于获取某种类型的所有key， 返回值为 key | key | key ... 是一个联合类型， K extends 是泛型约束 用于约束类型参数 K 对应的实际类型为 keyof 操作符拿到的所有 键组成的联合类型的子类型。 T[P] 用于获取 T 类型中 P 属性对应的类型，其中类型变量 P 的值会在遍历的过程中不断改变
type MyPick<T, K extends keyof T> = {
  [P in K]: T[P];
};
// 使用场景 通过 User 得到只有 id 和 name 的新类型
type User = {
  id: number;
  name: string;
  address: string;
};
type PickedUser = MyPick<User, "id" | "name">; // 得到 { id:number ; name:string }

// TS infer 类型 infer 只能在条件类型的 extends 子句中使用  infer 声明的类型变量 只在条件类型的 true 分支中可用
type UnpackedArray<T> = T extends (infer U)[] ? U : T; // 捕获数组中元素的类型
type UnpackedFn<T> = T extends (...args: any[]) => infer U ? U : T; // 获取函数的返回值类型
type Unpacked<T> = T extends (infer U)[]
  ? U
  : T extends (...args: any[]) => infer U
  ? U
  : T extends Promise<infer U>
  ? U
  : T; // 可获取数组中的类型，函数及promise的返回值类型
// 使用场景 获取T0 数组中 的类型
type T0 = string[];
type U0 = UnpackedArray<T0>; // string
// 使用场景  获取T1 函数类型的返回值类型, 遇到函数重载的时候， ts将使用最后一个调用签名进行类型推断
type T1 = () => string;
type U1 = UnpackedFn<T1>;
// 工具类型 Unpacked 的使用方法
type Unp0 = Unpacked<string>; // string
type Unp1 = Unpacked<string[]>; // string
type Unp2 = Unpacked<() => string>; // string
type Unp3 = Unpacked<Promise<string>>; // string
type Unp4 = Unpacked<Promise<string>[]>; // Promise<string>
type Unp5 = Unpacked<Unpacked<Promise<string>[]>>; // string

// 映射类型
// 语法: { readonly[P in K] ? : T}   readonly 表示添加只读修饰符， ？ 表示移除可选修饰符  默认前面是加号
// 常见映射类型语法：
// {[P in K] : T},{[P in K] ?: T},{[P in K] -?: T},{ readonly [P in K] : T},{ readonly [P in K] ?: T},{ -readonly [P in K] : T}
// 示例：
type Item = { a: string; b: number; c: boolean };
type N1 = { [P in "X" | "Y"]: number }; // {x:number,y:number}
type N2 = { [P in "X" | "Y"]: P }; // {x:'x',y:'y'}
type N3 = { [P in "a" | "b"]: Item[P] }; // {a:string,b:number}
type N4 = { [P in keyof Item]?: Item[P] }; // {a:string,b:number,c:boolean}  这里加了问号，意思得到的就全部都是可选类型了
// 可选类型转化工具类型
type Partia<T> = { [P in keyof T]?: T[P] };
// 同理 只读类型的转化工具类型
type myReadonly<T> = { readonly [P in keyof T]: T[P] };

// Record Record的内部定义，接收两个泛型参数；Record后面的泛型就是对象键和值的类型 作用 :定义一个对象的 key 和 value 类型
// 实现示例1：
type myRecord<K extends string | number | symbol, T> = {
  [P in K]: T;
};
// 实现示例2：
type myRecord2<K extends keyof any, T> = {
  [P in K]: T;
};

// Omit  工具类型 过滤对象类型中不需要的类型 实现 使用了 ts 内置的 pick 和 exclude Exclude 用于过滤掉 从keyof中要排除的类型 再使用pick 工具类型 从原有的对象类型中 挑选出需保留的属性 组合成新的对象类型
type myOmit<T, K extends keyof any> = Pick<T, Exclude<keyof T, K>>;
// 示例：
type User2 = {
  id: string;
  name: string;
  password: string;
  createAt: Date;
  update: Date;
};
type myUser2 = myOmit<User2, "id" | "createAt" | "update">; // {name:string,password:string}

// 模板字面量  类型使用 `${T}+change` T为传入的泛型 T 可以是 string | number | boolean | bigInt
// 示例：
type EventName<T extends string> = `${T}Change`;
type Concat<S1 extends string, S2 extends string> = `${S1}-${S2}`;
type Y1 = EventName<"foo">; // 'fooChange'
type Y2 = EventName<"foo" | "bar" | "bar2">; // 得到联合类型 'fooChange' | 'barChage' | 'bar2change'
type Y3 = Concat<"top" | "bottom", "left" | "right">; // 得到联合类型 'top-left' | 'top-right' | 'bottom-left' | bottom-right' 是因为多个占位符的联合类型会解析为叉积

// const 类型 可以在单个生命中来使用，禁止类型拓宽
let c = [1, { x: 2 }] as const; // 这样 c 的类型就变成了 只读类型， 也叫作类型收窄

// ts 内置的映射类型
/** 
Record<KeyUsage,Valuse> 键的类型为 keys，值的类型为 values
Partial<Object> 把 Object 中的每个字段都标记为可选的
Required<Object> 把 Object 中的每个字段都标记为必须的
Readonly<Object> 把 Object 中的每个字段都标记为只读的
Pick<Object,keys> 返回 Object 的子类型， 只含指定的 keys
*/
// ts 内置条件类型
/**
Exclude<T,U> 计算在 T 中 而不在 U 中的类型
type A = number | string
type B = string
type C = Exclude<A,B> // number
Extract<T,U> 计算 T 中可赋值给 U 的类型
type A = number | string
type B = string
type C = Extract<A,B> // string
NonNullable<T> 从 T 中排除 null 和 undefined
type A = {a?:number | null}
type B = NonNullable<A['a']> // number
RetrunType<F> 计算函数的返回类型（注意：不适用于泛型和重载的函数）
type F = (a:number) => string
type R = Return<F> // string
hook： const timeout = useRef<ReturnType<typeof setTimeout>>(); 
demo: type T1 = ReturnType<()=>string> // string
type T2 = ReturnType<(s:string)=>void> // void
type T3 = ReturnType<(<T>() => T)> // {}
type T4 = ReturnType<(<T extends U, U extends number[]>() => T)> // string
引用链接： https://blog.csdn.net/wu_xianqiang/article/details/115425818
InstanceType<T> 计算类构造方法的实例类型
type A = {new():B}
type B = {b:number}
type I = InstanceType<A> // {b:number}
 */
